/********************************************************
 *
 * FILE NAME:   signalprocessing.cpp
 *
 * DESCRIPTION:
 *  Module with signal processing primitives
 *
 ********************************************************/

/********************************************************/
/*              Includes                                */
/********************************************************/
#include "signalprocessing.h"

#include <QtQml>
#include <QDebug>
#include <algorithm>

/********************************************************/
/*              Defines                                 */
/********************************************************/

/********************************************************/
/*              Macros                                  */
/********************************************************/

/********************************************************/
/*              Typedefs                                */
/********************************************************/

/********************************************************/
/*              Local Functions Declarations (LOCAL)    */
/********************************************************/

/********************************************************/
/*              Global Variables (GLOBAL/IMPORT)        */
/********************************************************/

/********************************************************/
/*              Local Module Variables (MODULE)         */
/********************************************************/

/********************************************************/
/*              Local File Variables (LOCAL)            */
/********************************************************/

/********************************************************/
/*              Functions Definitions (LOCAL/GLOBAL)    */
/********************************************************/
ISignal::ISignal(size_t historyLength, size_t burstLength)
{
    _historyLength = historyLength;
    _burstLength = burstLength;

    _data = nullptr;
    _dataSize = 0;
    _dataStart = 0;

    _connectedTo = nullptr;
}

ISignal::~ISignal()
{
    if(_data != nullptr)
    {
        if(_connectedTo != nullptr)
        {
            _connectedTo->_data = nullptr;
        }
        delete[] _data;
    }
}

bool ISignal::isConnected()
{
    bool result;
    result = (_connectedTo != nullptr);

    return result;
}

size_t ISignal::burstLength()
{
    return _burstLength;
}

const sample_t & ISignal::operator[](size_t index) const
{
    index += _dataStart;
    index %= _dataSize;

    return _data[index];
}

bool ISignal::requestBurst(size_t burstLength)
{
    bool result;

    if(isConnected())
    {
        result = _connectedTo->onBurstRequest(burstLength);
    }else
    {
        result = false;
    }

    return result;
}

void ISignal::readInSample()
{
    _dataStart += _dataSize;
    --_dataStart;
    _dataStart %= _dataSize;
}

OSignal::OSignal(size_t historyLength)
{
    _historyLength = historyLength;

    _data = nullptr;
    _dataSize = 0;
    _dataStart = 0;

    _connectedTo = nullptr;
}

OSignal::~OSignal()
{
}

bool OSignal::isConnected()
{
    bool result;
    result = (_connectedTo != nullptr);

    return result;
}

size_t OSignal::burstLength()
{
    if(_connectedTo != nullptr)
    {
        return _connectedTo->_burstLength;
    }else
    {
        return 0;
    }
}

sample_t & OSignal::operator[](size_t index)
{
    index += _dataStart;
    index %= _dataSize;

    return _data[index];
}

void OSignal::writeOutSample()
{
    _dataStart += _dataSize;
    --_dataStart;
    _dataStart %= _dataSize;
}

SignalConnection::SignalConnection(QObject *parent) : QObject(parent)
{
}

void SignalConnection::registerTypes(const char *uri)
{
    qmlRegisterType<SignalConnection>(uri, 1, 0, "SignalConnection");
}

bool SignalConnection::connect(OSignal *out, ISignal *in)
{
    bool result;

    if(!in->isConnected() && !out->isConnected())
    {
        in->_dataSize = std::max(in->_historyLength + in->_burstLength, out->_historyLength) + 1;
        out->_dataSize = in->_dataSize;

        in->_dataStart = in->_dataSize;
        out->_dataStart = out->_dataSize - 1;

        in->_data = new sample_t[in->_dataSize];
        out->_data = in->_data;

        for(size_t i = 0; i < in->_dataSize; ++i)
        {
            in->_data[i] = 0;
        }

        in->_connectedTo = out;
        out->_connectedTo = in;

        result = true;
    }else
    {
        result = false;
    }

    return result;
}

bool SignalConnection::connect(void *out, void *in)
{
    return connect((OSignal *) out, (ISignal *) in);
}
